package es.duma.search;

import es.duma.search.Repository;
import es.duma.util.log.Log;
import es.duma.util.config.Configurator;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.Vector;

/**
 * Gestiona las operaciones sobre los repositorios configurados del sistema.
 * Matiene una lista de objetos Repository.
 * Se implementan las operaciones de persistencia
 */
public class RepositoryManager {

    /**
     * Driver de MySql por defecto
     */
    private static final String MYSQL_Driver_default="com.mysql.jdbc.Driver";
    private static String MYSQL_Driver=MYSQL_Driver_default;
    
    /**
     * Usuario Mysql por defecto
     */
    private static final String MYSQL_User_default="root";
    private static String MYSQL_User=MYSQL_User_default;
    
    /**
     * Password de MySql por defecto
     */
    private static final String MYSQL_Passw_default="clave12m";
    private static String MYSQL_Passw=MYSQL_Passw_default;
    
    /**
     * Url jdbc definida por defecto
     * 
     */
    private static final String MYSQL_Url_default="jdbc:mysql://localhost/duma";
    private static String MYSQL_Url=MYSQL_Url_default;
    
    /**
     * Nombre de la tabla de repositorios por defecto
     */
    private static final String MYSQL_table_reposit_default="repositorios";
    private static String MYSQL_table_reposit=MYSQL_table_reposit_default;
    
    /**
     * Atributos de la tabla que relacionan a cada atributo de la clase
     */
    public static final String ATR_ID="id";
    public static final String ATR_NAME="nombre";
    public static final String ATR_XSL="xsl";
    public static final String ATR_URL_WEB="urlweb";
    public static final String ATR_ACTIVE="activo";
    public static final String ATR_MAX_RESULTS="maxResults";
    public static final String ATR_TIPO_CONTENIDO="tipoContenido";

    
    /**
     * Nombre de la clase para mostrar en los mensajes de log del sistema
     */
    private static final String CLASSNAME="[RepositoryManager]";
    
    /**
     * Lista con los repositorios configurados en el sistema
     * 
     */
    private static ArrayList repositories=null;
    
    /**
     * Tipo de contenido permitido
     */
    private static Vector tipoContenido=new Vector();
    
    
    /**
     * Devuelve una lista de los repositorios activos en el sistema
     * @return lista de objetos Repository
     */
    public static ArrayList getActiveRepositories(){
        Log.debug(CLASSNAME+" Se solicita la lista de repositorios activos");
        init(false);
        
        Iterator it=repositories.iterator();
        ArrayList results=new ArrayList();
        
        while (it.hasNext()){
            Repository repository =(Repository)it.next();
            if (repository.isActive()){
                results.add(repository);                
            }
        }
        Log.debug(CLASSNAME+" Se han encontrado "+results.size()+" repositorios activos");
        return results;
        
        
    }
    
    /**
     * Devuelve una lista con todos los repositorios del sistema
     * @return lista de objetos Repository
     */
    public static ArrayList getRepositories(){
        Log.debug(CLASSNAME+" Se solicita la lista de repositorios");
        init(false);
        
        Iterator it=repositories.iterator();
        ArrayList results=new ArrayList();
        
        while (it.hasNext()){
            Repository repository =(Repository)it.next();
            results.add(repository);                
        }
        Log.debug(CLASSNAME+" Se han encontrado "+results.size()+" repositorios");
        return results;
        
    }
    
    
    /**
     * Busca un repositorio por identificador, de entre los que estan configurados en el sistema
     * @param id
     * @return objeto Repository encontrado o null si no ha sido encontrado
     */
    public static Repository getRepositoryById(String id){
        Log.debug(CLASSNAME+" Se solicita los detalles de un repositorio en concreto. Se busca por id "+id);
        init(false);
        
        Iterator it=repositories.iterator();
        ArrayList results=new ArrayList();
        
        while (it.hasNext()){
            Repository repository =(Repository)it.next();
            if ((repository.getId()).equalsIgnoreCase(id)){
                return repository;
            }
        }
        Log.debug(CLASSNAME+" No se ha encontrado el repositorio solicitado por id "+id);
        return null;
    }
    
    
    /**
     * Comprueba la existencia de un determinado repositorio en el sistema
     * @param rep se busca por el id del objeto Repository
     * @return true si existe o false si no existe en el sistema
     */
    public static boolean existRepository(Repository rep){
        Log.debug(CLASSNAME+" Se comprueba si existe el repositorio con id "+rep.getId());
        
        Iterator it=repositories.iterator();    
        while (it.hasNext()){
            Repository repository =(Repository)it.next();
            if ((repository.getId()).equalsIgnoreCase(rep.getId())){
                Log.debug(CLASSNAME+" El repositorio "+rep.getId()+" ya esta dado de alta");
                return true;
            }
        }
        Log.debug(CLASSNAME+" El repositorio "+rep.getId()+" no exite en el sistema");
        return false;
        
    }
    
    
    /**
     * Actualiza en la base de datos los atributos del repositorio pasado por parametro
     * @param rep Objeto Repository que se quiere alamcenar en la BD
     * @return true si la operacion se ha realizado correctamente, false en caso contrario
     */
    public static boolean updateRepository(Repository rep){
         Connection jdbcConnection = null;
         try {
             Class.forName(MYSQL_Driver).newInstance();
             jdbcConnection = DriverManager.getConnection(MYSQL_Url,MYSQL_User,MYSQL_Passw);
             
             Statement stmt = jdbcConnection.createStatement();
             String query="UPDATE "
             +MYSQL_table_reposit+" SET "+ATR_NAME+"=\'"+rep.getNombre()+"\', " +
             ATR_MAX_RESULTS+"=\'"+rep.getMaxResults()+"\', "+
             ATR_ACTIVE+"=\'" +rep.isActiveInt()+"\'"+          

             "WHERE "+ATR_ID+"="+"\'"+rep.getId()+"\' ";
             
             
             Log.debug("Query "+query);
             stmt.execute(query);
             
         } catch (IllegalAccessException e) {
             Log.error(CLASSNAME+" Ha ocurriro un error "+e);
             return false;
         } catch (InstantiationException e) {
             Log.error(CLASSNAME+" Ha ocurriro un error "+e);
             return false;
         } catch (SQLException e) {
             Log.error(CLASSNAME+" Ha ocurriro un error "+e);
             return false;
         } catch (ClassNotFoundException e) {
             Log.error(CLASSNAME+" Ha ocurriro un error "+e);
             return false;
         }
         
         // Una vez realizado el update en la base de datos hay que invalidar el repositorio que se encuentra "cacheado" en el ArrayList repositories
         init(true);
         return true;
        
    }
    
    /**
     * Almacena en la base de datos los atributos del repositorio pasado por parametro
     * @param rep Objeto Repository que se quiere alamcenar en la BD
     * @return true si la operacion se ha realizado correctamente, false en caso contrario
     */
    public static boolean saveRepository(Repository rep){
        Log.debug(CLASSNAME+" Se inicia el proceso de almacenar el repositorio en la BD");
        // Se comprueba si el repositorio existe. Entonces es una actualización.
        if (existRepository(rep)){
            Log.debug(CLASSNAME+" El repositorio ya existe en la BD. Se trata de una actualizacion.");
            return updateRepository(rep);
        }
        // El repositorio es nuevo en el sistema. Se inserta en la BD
        Connection jdbcConnection = null;
        try {
            Class.forName(MYSQL_Driver).newInstance();
            jdbcConnection = DriverManager.getConnection(MYSQL_Url,MYSQL_User,MYSQL_Passw);
            
            Statement stmt = jdbcConnection.createStatement();
            String query="INSERT INTO "
            +MYSQL_table_reposit+" ("+
            ATR_ID+","+
            ATR_NAME+","+
            ATR_XSL+","+
            ATR_URL_WEB+","+
            ATR_ACTIVE+","+
            ATR_MAX_RESULTS+","+
            ATR_TIPO_CONTENIDO+           

            ") VALUES ( '"+
            rep.getId()+"','"+
            rep.getNombre()+"','"+
            rep.getXsl()+"','"+
            rep.getUrlWeb()+"','"+
            rep.isActiveInt()+"','"+
            rep.getMaxResults()+"','"+
            rep.getTipoContenido()+"');";
            
            
            Log.debug("Query "+query);
            stmt.execute(query);
             } catch (IllegalAccessException e) {
                 Log.error(CLASSNAME+" Ha ocurriro un error "+e);
                 return false;
             } catch (InstantiationException e) {
                 Log.error(CLASSNAME+" Ha ocurriro un error "+e);
                 return false;
             } catch (SQLException e) {
                 Log.error(CLASSNAME+" Ha ocurriro un error "+e);
                 return false;
             } catch (ClassNotFoundException e) {
                 Log.error(CLASSNAME+" Ha ocurriro un error "+e);
                 return false;
             }
        
        // Una vez realizado el update en la base de datos hay que invalidar el repositorio que se encuentra "cacheado" en el ArrayList repositories
        init(true);
        return true;
    }
    
    /**
     * Elimina de la base de datos el repositorio pasado por parametro
     * @param rep Objeto Repository que se quiere eliminar de la BD
     * @return true si la operacion se ha realizado correctamente, false en caso contrario
     */
    public static boolean deleteRepository(Repository rep){
        Log.debug(CLASSNAME+" Se inicia el proceso de eliminacion del repositorio en la BD");
        // Se comprueba si el repositorio existe.
        if (existRepository(rep)){
            Log.debug(CLASSNAME+" Listo para eliminar.");
                       
            Connection jdbcConnection = null;
            try {
                Class.forName(MYSQL_Driver).newInstance();
                jdbcConnection = DriverManager.getConnection(MYSQL_Url,MYSQL_User,MYSQL_Passw);
                
                Statement stmt = jdbcConnection.createStatement();
                String query="DELETE FROM `repositorios` WHERE CONVERT(`repositorios`.`id` USING utf8) ='"+rep.getId()+"' LIMIT 1;";
                
                Log.debug("Query "+query);
                stmt.execute(query);
                 } catch (IllegalAccessException e) {
                     Log.error(CLASSNAME+" Ha ocurriro un error "+e);
                     return false;
                 } catch (InstantiationException e) {
                     Log.error(CLASSNAME+" Ha ocurriro un error "+e);
                     return false;
                 } catch (SQLException e) {
                     Log.error(CLASSNAME+" Ha ocurriro un error "+e);
                     return false;
                 } catch (ClassNotFoundException e) {
                     Log.error(CLASSNAME+" Ha ocurriro un error "+e);
                     return false;
                 }
        
                // Una vez realizado la eliminacion en la base de datos hay que invalidar el repositorio que se encuentra "cacheado" en el ArrayList repositories
                init(true);
                return true;
        }
        return false;
    }
    
    
    /**
     * Devuelve la lista de contenidos permitidos para un repositorio
     * @return
     */
    public static Vector getTiposContenido(){
        if (tipoContenido==null){
            Log.debug(CLASSNAME+" Se cargan los tipos de contenido validos");
            tipoContenido=new Vector();
            tipoContenido.add("video");
            tipoContenido.add("foto");
            tipoContenido.add("sonido");
            tipoContenido.add("texto");
            tipoContenido.add("varios");
        }
    
        return tipoContenido;
    }
    
    /**
     * Carga la configuracion de los repositorios desde la base de datos
     * @param force fuerza a recargar la configuracion si vale true
     */
    public static void init(boolean force){
    
        MYSQL_Driver=Configurator.getPropertieValue("MYSQL_Driver");
        MYSQL_User=Configurator.getPropertieValue("MYSQL_User");
        MYSQL_Passw=Configurator.getPropertieValue("MYSQL_Passw");
        MYSQL_Url=Configurator.getPropertieValue("MYSQL_Url");
        MYSQL_table_reposit=Configurator.getPropertieValue("MYSQL_table_reposit");
        
        
        if (repositories==null || force ){
            Log.debug(CLASSNAME+" Se inicializa el RepositoryManager");
            Connection jdbcConnection = null;
            repositories = new ArrayList();
            try{
                Class.forName(MYSQL_Driver).newInstance();
                jdbcConnection = DriverManager.getConnection(MYSQL_Url,MYSQL_User,MYSQL_Passw);
                
                Statement stmt = jdbcConnection.createStatement();
                
                ResultSet results = stmt.executeQuery("SELECT * FROM "+MYSQL_table_reposit);
                Log.debug(CLASSNAME+" Se realiza la consulta a la base de datos");
                int num=0;
                
                while (results.next()){
                    System.out.println( "Repositorio "+results.getString("nombre") );
                    Repository rep=new Repository(results.getString(ATR_ID),results.getString(ATR_NAME),results.getString(ATR_XSL),results.getString(ATR_URL_WEB),results.getBoolean(ATR_ACTIVE),results.getInt(ATR_MAX_RESULTS),results.getString(ATR_TIPO_CONTENIDO));
                    Log.debug(CLASSNAME+" Se inserta en la lista de repositorios");
                    repositories.add(rep);
                    num++;
                }
                
                Log.debug(CLASSNAME+" Numero de repositorios obtenido "+num);
                results.close();
                
            }catch ( Exception e ){
                System.out.println("Ha ocurrido un error al conectar a la base de datos "+e);
            }finally{
                try{
                    jdbcConnection.close();
                }catch(Exception e){
                    System.out.println("error al cerrar la conexion "+e);
                }
            }
        }
        
    }
    
}
